using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SQLite;
using System.IO;
using System.Windows.Forms;
using System.Drawing;
using LeisureCenter.Api;
using LeisureCenter.Core;
using LeisureCenter.Tools;
using LeisureCenter.OptionsForms;
using LeisureCenter.LeisureCenterDataSetTableAdapters;

namespace LeisureCenter.BrowserItems
{
    public abstract class BaseLibraryBrowserItem : IBrowserItem
    {
        protected IBrowserFolderItem folder;
        protected string text;

        protected BaseLibraryBrowserItem(IBrowserFolderItem folder, string text)
        {
            this.folder = folder;
            if (!string.IsNullOrEmpty(text))
                this.text = text;
            else
                this.text = @"<<Empty>>";
        }

        #region IBrowserItem Membres

        public string Text { get { return text; } }

        public abstract string IconName { get; }

        public virtual string Description { get { return ""; } }

        public IBrowserFolderItem Folder { get { return this.folder; } }

        public abstract void Execute();

        public virtual void AlternateExecute()
        {
        }

        public virtual void OptionsExecute()
        {
        }

        public virtual string Thumbnail { get { return ""; } }

        #endregion
    }

    public interface ILibraryBrowserObjectItem
    {
        string FileName { get; }
    }

    public class LibraryBrowserObjectItem : BaseLibraryBrowserItem, ILibraryBrowserObjectItem
    {
        private string fileName;

        public LibraryBrowserObjectItem(IBrowserFolderItem folder, string fileName, string text)
            : base(folder, text)
        {
            this.fileName = fileName;
        }

        public override string IconName
        {
            get { return @"default"; }
        }

        public override string Description { get { return this.fileName; } }

        public override void Execute()
        {
            List<string> filenames = new List<string>();
            int index = 0;
            bool selfSeen = false;
            foreach (IBrowserItem item in folder.Items)
            {
                if (item is ILibraryBrowserObjectItem)
                {
                    if (selfSeen || item == this)
                    {
                        selfSeen = true;
                        filenames.Insert(index, ((ILibraryBrowserObjectItem)item).FileName);
                        index++;
                    }
                    else
                    {
                        filenames.Add(((ILibraryBrowserObjectItem)item).FileName);
                    }
                }
            }
            Program.LeisureCenterInstance.PlaylistManager.AddFromFileNames(filenames, true);
            Program.LeisureCenterInstance.MainForm.FocusPlaylist();
        }

        public override void AlternateExecute()
        {
            Program.LeisureCenterInstance.PlaylistManager.AddFromFileName(this.FileName, false);
        }

        public override void OptionsExecute()
        {
            LibraryObjectOptionsDialog dialog = new LibraryObjectOptionsDialog(this.fileName);
            using (dialog)
            {
                dialog.Title = this.fileName;
                FilesTableAdapter filesTableAdapter = new FilesTableAdapter();
                LeisureCenterDataSet.FilesDataTable filesDataTable = filesTableAdapter.GetFilesByFilename(this.fileName);
                if (filesDataTable != null && filesDataTable.Count > 0)
                {
                    LeisureCenterDataSet.FilesRow row = filesDataTable[0];
                    if (!row.IsRatingNull())
                        dialog.ratingBar1.Rating = (int)row.Rating;
                    else
                        dialog.ratingBar1.Rating = 0;
                    dialog.LibraryId = row.LibraryId;
                    if (dialog.Execute())
                    {
                        if (row.IsRatingNull() || row.Rating != dialog.ratingBar1.Rating || row.LibraryId != dialog.LibraryId)
                        {
                            if (dialog.ratingBar1.Rating > 0)
                                row.Rating = dialog.ratingBar1.Rating;
                            else
                                row.SetRatingNull();
                            row.LibraryId = dialog.LibraryId;
                            filesTableAdapter.Update(filesDataTable);
                        }
                    }
                }
            }
        }

        #region ILibraryBrowserObjectItem Membres

        public string FileName { get { return this.fileName; } }

        #endregion
    }

    public class UniqueList<T> : List<T>
    {
        IEqualityComparer<T> comparer;

        public UniqueList(IEqualityComparer<T> comparer)
        {
            this.comparer = comparer;
        }

        public new void Add(T item)
        {
            if (!Contains(item))
                base.Add(item);
        }

        public new bool Contains(T item)
        {
            if (item == null)
            {
                for (int num1 = 0; num1 < Count; num1++)
                {
                    if (this[num1] == null)
                    {
                        return true;
                    }
                }
                return false;
            }
            for (int num2 = 0; num2 < Count; num2++)
            {
                if (this.comparer.Equals(this[num2], item))
                {
                    return true;
                }
            }
            return false;
        }
    }

    public struct QueryItems
    {
        public QueryItems(IEnumerable<string> tables, IEnumerable<string> wheres, IEnumerable<string> tempWheres, IEnumerable<string> titleParts)
        {
            this.Tables = tables;
            this.Wheres = wheres;
            this.TempWheres = tempWheres;
            this.TitleParts = titleParts;
        }

        public IEnumerable<string> Tables;
        public IEnumerable<string> Wheres;
        public IEnumerable<string> TempWheres;
        public IEnumerable<string> TitleParts;
    }

    public abstract class BaseLibraryBrowserFolderItem : BaseLibraryBrowserItem, IBrowserFolderItem
    {
        internal protected List<IBrowserItem> items;
        protected List<string> tables = new List<string>(new string[] { "Files" });
        protected List<string> wheres = new List<string>();
        protected List<string> tempWheres = new List<string>();
        protected List<string> titleParts = new List<string>();
        private bool oneFolder;

        protected BaseLibraryBrowserFolderItem(IBrowserFolderItem folder, string text, QueryItems queryItems)
            : base(folder, text)
        {
            if (queryItems.Tables != null)
                this.tables.AddRange(queryItems.Tables);
            if (queryItems.Wheres != null)
                this.wheres.AddRange(queryItems.Wheres);
            if (queryItems.TempWheres != null)
                this.tempWheres.AddRange(queryItems.TempWheres);
            if (queryItems.TitleParts != null)
                this.titleParts.AddRange(queryItems.TitleParts);
        }

        protected string GetWhereCondition()
        {
            if (this.wheres.Count == 0 && this.tempWheres.Count == 0)
                return "";
            else
            {
                List<string> checkedWheres = new List<string>();
                foreach (string where in this.wheres)
                    if (!checkedWheres.Contains(where))
                        checkedWheres.Add(where);
                foreach (string where in this.tempWheres)
                    if (!checkedWheres.Contains(where))
                        checkedWheres.Add(where);

                string result = "where " + checkedWheres[0];
                for (int i = 1; i < checkedWheres.Count; i++)
                    result += " and " + checkedWheres[i];
                return result;
            }
        }

        protected string GetTables()
        {
            if (this.tables.Count == 0)
                throw new Exception("No tables found in query!");
            else
            {
                UniqueList<string> checkedItems = new UniqueList<string>(StringComparer.OrdinalIgnoreCase);
                foreach (string item in this.tables)
                    checkedItems.Add(item);

                string result = checkedItems[0];
                for (int i = 1; i < checkedItems.Count; i++)
                    result += ", " + checkedItems[i];
                return result;
            }
        }

        protected void ExecuteQuery(string query)
        {
            this.items = new List<IBrowserItem>();
            SQLiteConnection connection = new SQLiteConnection(Properties.Settings.Default.ConnectionString);
            connection.Open();
            try
            {
                SQLiteCommand command = connection.CreateCommand();
                command.CommandText = query;
                SQLiteDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    ReadQueryItem(reader);
                }
            }
            finally
            {
                connection.Close();
            }
        }

        protected abstract void ReadQueryItem(SQLiteDataReader reader);

        protected virtual void OnItemsChanged()
        {
            EventHandler temp = this.ItemsChanged;
            if (temp != null)
            {
                if (!Program.LeisureCenterInstance.MainForm.InvokeRequired)
                    temp(this, null);
                else
                {
                    Program.LeisureCenterInstance.MainForm.Invoke(temp, this, null);
                }
            }
        }

        public override string IconName { get { return @"folder"; } }

        public override void Execute()
        {
            Program.LeisureCenterInstance.BrowserManager.Browse(this);
        }

        protected abstract void CreateItems();

        protected virtual void CreateGeneralItems() { }

        #region IBrowserFolderItem Membres

        public IEnumerable<IBrowserItem> Items
        {
            get 
            {
                if (this.items == null)
                {
                    CreateItems();
                    if (this.items.Count == 1 && this.items[0] is IBrowserFolderItem)
                    {
                        CreateGeneralItems();
                        this.oneFolder = true;
                        return ((IBrowserFolderItem)this.items[0]).Items;
                    }
                    CreateGeneralItems();
                }
                else
                    if (this.oneFolder)
                        return ((IBrowserFolderItem)this.items[0]).Items;
                return items;
            }
        }

        public string Title
        {
            get
            {
                string result = "";
                foreach (string titlePart in this.titleParts)
                    result += @"\" + titlePart;
                return result;
            }
        }

        public override void OptionsExecute()
        {
            LeisureCenterDataSet.FilesDataTable filesDataTable = new LeisureCenterDataSet.FilesDataTable();
            using (SQLiteConnection connection = new SQLiteConnection(Properties.Settings.Default.ConnectionString))
            {
                using (SQLiteDataAdapter filesTableAdapter = new SQLiteDataAdapter())
                {
                    filesTableAdapter.SelectCommand = new SQLiteCommand(string.Format(@"SELECT Files.* FROM {0} {1}", GetTables(), GetWhereCondition()), connection);
                    filesTableAdapter.UpdateCommand = new SQLiteCommand(@"UPDATE [Files] SET [filename] = @filename, [dataHash] = @dataHash, [kind] = @kind, [lastModified] = @lastModified, [addedDatetime] = @addedDatetime, [rating] = @rating, [deleted] = @deleted, [updatedDatetime] = @updatedDatetime, [libraryId] = @libraryId WHERE (([id] = @Original_id) AND ((@IsNull_filename = 1 AND [filename] IS NULL) OR ([filename] = @Original_filename)) AND ((@IsNull_dataHash = 1 AND [dataHash] IS NULL) OR ([dataHash] = @Original_dataHash)) AND ((@IsNull_kind = 1 AND [kind] IS NULL) OR ([kind] = @Original_kind)) AND ((@IsNull_lastModified = 1 AND [lastModified] IS NULL) OR ([lastModified] = @Original_lastModified)) AND ((@IsNull_addedDatetime = 1 AND [addedDatetime] IS NULL) OR ([addedDatetime] = @Original_addedDatetime)) AND ((@IsNull_rating = 1 AND [rating] IS NULL) OR ([rating] = @Original_rating)) AND ((@IsNull_deleted = 1 AND [deleted] IS NULL) OR ([deleted] = @Original_deleted)) AND ((@IsNull_updatedDatetime = 1 AND [updatedDatetime] IS NULL) OR ([updatedDatetime] = @Original_updatedDatetime)) AND ([libraryId] = @Original_libraryId))", connection);
                    SQLiteParameter param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@filename";
                    param.DbType = System.Data.DbType.String;
                    param.SourceColumn = "filename";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@dataHash";
                    param.DbType = System.Data.DbType.String;
                    param.SourceColumn = "dataHash";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@kind";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "kind";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@lastModified";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "lastModified";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@addedDatetime";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "addedDatetime";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@rating";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "rating";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@deleted";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "deleted";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@updatedDatetime";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "updatedDatetime";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@libraryId";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "libraryId";
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_id";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "id";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@IsNull_filename";
                    param.DbType = System.Data.DbType.Int32;
                    param.DbType = System.Data.DbType.Int32;
                    param.SourceColumn = "filename";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    param.SourceColumnNullMapping = true;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_filename";
                    param.DbType = System.Data.DbType.String;
                    param.SourceColumn = "filename";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@IsNull_dataHash";
                    param.DbType = System.Data.DbType.Int32;
                    param.DbType = System.Data.DbType.Int32;
                    param.SourceColumn = "dataHash";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    param.SourceColumnNullMapping = true;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_dataHash";
                    param.DbType = System.Data.DbType.String;
                    param.SourceColumn = "dataHash";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@IsNull_kind";
                    param.DbType = System.Data.DbType.Int32;
                    param.DbType = System.Data.DbType.Int32;
                    param.SourceColumn = "kind";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    param.SourceColumnNullMapping = true;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_kind";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "kind";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@IsNull_lastModified";
                    param.DbType = System.Data.DbType.Int32;
                    param.DbType = System.Data.DbType.Int32;
                    param.SourceColumn = "lastModified";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    param.SourceColumnNullMapping = true;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_lastModified";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "lastModified";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@IsNull_addedDatetime";
                    param.DbType = System.Data.DbType.Int32;
                    param.DbType = System.Data.DbType.Int32;
                    param.SourceColumn = "addedDatetime";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    param.SourceColumnNullMapping = true;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_addedDatetime";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "addedDatetime";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@IsNull_rating";
                    param.DbType = System.Data.DbType.Int32;
                    param.DbType = System.Data.DbType.Int32;
                    param.SourceColumn = "rating";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    param.SourceColumnNullMapping = true;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_rating";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "rating";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@IsNull_deleted";
                    param.DbType = System.Data.DbType.Int32;
                    param.DbType = System.Data.DbType.Int32;
                    param.SourceColumn = "deleted";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    param.SourceColumnNullMapping = true;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_deleted";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "deleted";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@IsNull_updatedDatetime";
                    param.DbType = System.Data.DbType.Int32;
                    param.DbType = System.Data.DbType.Int32;
                    param.SourceColumn = "updatedDatetime";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    param.SourceColumnNullMapping = true;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_updatedDatetime";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "updatedDatetime";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    param = new System.Data.SQLite.SQLiteParameter();
                    param.ParameterName = "@Original_libraryId";
                    param.DbType = System.Data.DbType.Int64;
                    param.DbType = System.Data.DbType.Int64;
                    param.SourceColumn = "libraryId";
                    param.SourceVersion = System.Data.DataRowVersion.Original;
                    filesTableAdapter.UpdateCommand.Parameters.Add(param);
                    filesTableAdapter.Fill(filesDataTable);
                    LibraryFolderOptionsDialog dialog = new LibraryFolderOptionsDialog(filesDataTable);
                    using (dialog)
                    {
                        dialog.Title = this.text;
                        dialog.btnRefresh.Click += new EventHandler(btnRefresh_Click);
                        if (dialog.Execute())
                            filesTableAdapter.Update(filesDataTable);
                    }
                }
            }
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            IEnumerable<string> fileNames = DatabaseManager.ExecuteStringsQuery(string.Format(@"SELECT filename FROM {0} {1}", GetTables(), GetWhereCondition()));
            foreach (string fileName in fileNames)
            {
                Program.LeisureCenterInstance.libraryManager.filesCheckerThread.AddFile(new FileInfo(fileName), true);
                Program.LeisureCenterInstance.libraryManager.filesCheckerThread.Wakeup();
            }
        }

        public void Refresh()
        {
            // TODO
        }

        public event EventHandler ItemsChanged;

        #endregion
    }
}
